/**********************************************************************/
/* Programa: COMPRESOR 
Este programa es el ejecutable del tp de Organización de datos
Integrantes        : Catalina Windmuller, Ayelén Tamiozzo y Francisco Soler               
Fecha              : 17 de abril de 2011                                 
Versión            : 01                                                     
Nombre del archivo : TPGrupoXX.c */

/**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "lista_circular.h"
#include "block_sorting.h"
#include "estructurado.h"
#include "cola.h"
#include "MTF.h"
#include "time.h"
#define ERROR 			-1
#define COMPRIMIR 		1
#define DESCOMPRIMIR 	2
#define EXTENSIONDES	".05" //el 01 se cambia cuando se sepa el numero del grupo
int parametros_correctos (int argc, char *argv[]){
	int devolver;
	if (argc != 3){
		return (ERROR);
	}
	int largo = strlen (argv[2]);
	
	if (!strcmp(argv [1], "-x") && !strcmp(argv [2] + largo - 3, EXTENSIONDES)){
		devolver = DESCOMPRIMIR;
	}
	else if (!strcmp(argv [1], "-c")){
		devolver = COMPRIMIR;
	}
	else {
		return ERROR;
	}
	
	FILE* archivo = fopen(argv[2], "r");
	if (archivo == NULL) {
		return ERROR;
	}
	fclose (archivo);
	return devolver;
}
	
int main(int argc, char *argv[]) {
	int parametros_ok = parametros_correctos (argc, argv);
	time_t now1 = time(0);
	if (parametros_ok == ERROR){
		printf("El presente programa requiere como parámetros la acción (-c, -x)\n");
		printf("y el nombre de un archivo existente con extension %s (-x) \n",EXTENSIONDES);
		return -1;
	}
	unsigned char *buffer = (unsigned char*) malloc (sizeof(char) * (TAMANIOBUFFER + 2));
	FILE* archivo = fopen(argv[2], "r");
	size_t cantidad_leidos;
	bool primera_vuelta = true;
	do{ 
		unsigned char* resultado = (unsigned char*) malloc (sizeof(char) * TAMANIOBUFFER * 50);
		if (parametros_ok == COMPRIMIR) {
			cantidad_leidos = fread (buffer, sizeof(char), TAMANIOBUFFER, archivo);
			if(cantidad_leidos == 0)
				break;
			buffer[cantidad_leidos] = '\0';
			tlista lista;
			Crear_Lista(&lista);
			int tamanio_resultado;
			unsigned char *L;
			uint32_t I;
			tcola cola_mtf;
			crear_cola(&cola_mtf);
			int i;
			for (i = 0; i < cantidad_leidos; i++) {
				unsigned char *dato = (unsigned char*) malloc (sizeof(char));
				*dato = buffer[i];
				Insertar_Lista_Final (&lista, (tdatol) dato);
			}
			compresion_block_sorting(lista, &L, &I);
			comprimir_mtf(&cola_mtf, L, cantidad_leidos);
			comprimir_estructurado(cola_mtf, resultado, &tamanio_resultado);
			char* nombre = (char*) malloc (sizeof(char) * (strlen(argv[2]) + 4));
			strcpy (nombre, argv[2]);
			strcat(nombre, ".05");
			FILE* archivo;
			if (primera_vuelta) {
				archivo = fopen(nombre, "w+");
				primera_vuelta = false;
			}else
				archivo = fopen(nombre, "a");
			unsigned char *tamanio_comprimido = (unsigned char*) malloc (sizeof(char) * 4);
			unsigned char *tamanio_archivo = (unsigned char*) malloc (sizeof(char) * 4);
			unsigned char *numeroI = (unsigned char*) malloc (sizeof(char) * 4);
			numeroI[3] = '\0';
			numeroI[0] = I >> 16;
			numeroI[1] = (I << 16) >> 24;
			numeroI[2] = (I << 24) >> 24;
			tamanio_archivo[3] = '\0';
			tamanio_archivo[0] = cantidad_leidos >> 16;
			tamanio_archivo[1] = (cantidad_leidos << 16) >> 24;
			tamanio_archivo[2] = (cantidad_leidos << 24) >> 24;
			tamanio_comprimido[3] = '\0';
			tamanio_comprimido[0] = tamanio_resultado >> 16;
			tamanio_comprimido[1] = (tamanio_resultado << 16) >> 24;
			tamanio_comprimido[2] = (tamanio_resultado << 24) >> 24;
			fwrite(tamanio_archivo, sizeof(char), 3, archivo);
			fwrite(tamanio_comprimido, sizeof(char), 3, archivo);
			fwrite(numeroI, sizeof(char), 3, archivo);
			fwrite(resultado, sizeof(char), tamanio_resultado, archivo);
			free(tamanio_comprimido);
			free(numeroI);
			free(tamanio_archivo);
			fclose (archivo);
			free (resultado);
			free (nombre);
		}
		else if (parametros_ok == DESCOMPRIMIR) {
			unsigned char *tamanio_comprimido = (unsigned char*) malloc (sizeof(char)*4);
			unsigned char *tamanio_archivo = (unsigned char*) malloc (sizeof(char)*4);
			unsigned char *numeroI = (unsigned char*) malloc (sizeof(char)*4);
			tamanio_comprimido[3] = '\0';
			tamanio_archivo[3] = '\0';
			numeroI[3] = '\0';
			fread (tamanio_archivo, sizeof(char), 3, archivo);
			fread (tamanio_comprimido, sizeof(char), 3, archivo);
			fread (numeroI, sizeof(char), 3, archivo);
			cantidad_leidos = (tamanio_archivo[0] << 16) + (tamanio_archivo[1] << 8) + tamanio_archivo[2];
			int tam_comp = (tamanio_comprimido[0] << 16) + (tamanio_comprimido[1] << 8) + tamanio_comprimido[2];
			int I = (numeroI[0] << 16) + (numeroI[1] << 8) + numeroI[2];
			size_t cantidad_leidos2 = fread (buffer, sizeof(char), tam_comp, archivo);
			FILE* archivo;
			if(cantidad_leidos2 == 0)
				break;
			buffer[cantidad_leidos2] = '\0';
			tcola cola_mtf;
			crear_cola(&cola_mtf);
			descomprimir_estructurado(buffer, &cola_mtf, cantidad_leidos2, cantidad_leidos);
			size_t largo = ver_largo_cola(cola_mtf);
			unsigned char *vec_ult_col = (unsigned char*) malloc (sizeof(char) * largo);
			descomprimir_mtf(vec_ult_col, &cola_mtf);
			descompresion_block_sorting(resultado, vec_ult_col, I, largo);
			char* nombre = (char*) malloc (sizeof(char)* (strlen (argv[2]) + 4));
			strncpy (nombre, argv[2], strlen(argv[2])-3);
			nombre [strlen(argv[2])-3] = '\0';
			
			if (primera_vuelta) {
				archivo = fopen(nombre, "w+");
				primera_vuelta = false;
			}else
				archivo = fopen(nombre, "a");
			
			fwrite(resultado, sizeof(char), largo, archivo); 
			free(tamanio_comprimido);
			free(numeroI);
			fclose (archivo);
			free (resultado); 
			free (nombre);
		}
	} while  (cantidad_leidos == TAMANIOBUFFER);//fread devuelve el largo de la cadena
	
	time_t now = time(0);
	time_t a = now - now1;
	struct tm  *ts;
    char       buf[80];
	ts = localtime(&a);
    strftime(buf, sizeof(buf), "%M:%S", ts);
    printf("duración en min, seg %s\n", buf);
	free (buffer);
	return (0);
}
